package cc.eddic.practice.concurrency.impl;

import cc.eddic.practice.concurrency.LogItem;
import cc.eddic.practice.concurrency.LogParser;

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

public class LogParserWithExecutorCxmImpl implements LogParser {
    private static final int NUM_THREADS = Runtime.getRuntime().availableProcessors();
    @Override
    public Map<String, List<LogItem>> parse(String folderName) {
        ConcurrentHashMap<String, List<LogItem>> map = new ConcurrentHashMap<>();

        ExecutorService executor = Executors.newFixedThreadPool(NUM_THREADS);
        try {
            List<Callable<Void>> tasks = new ArrayList<>();

            Files.walk(Paths.get(folderName))
                    .parallel()
                    .forEach(path -> {
                        if (path.toString().endsWith(".log")) {
                            Callable<Void> task = () -> {
                                try (BufferedReader reader = Files.newBufferedReader(path)) {
                                    List<LogItem> logItems = new ArrayList<>();
                                    String line;
                                    while ((line = reader.readLine()) != null) {
                                        new LogItemParserCxmImpl().parse(line).ifPresent(logItems::add);
                                    }
                                    map.putIfAbsent(path.getFileName().toString(), logItems);
                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                                return null;
                            };
                            tasks.add(task);
                        }
                    });

            executor.invokeAll(tasks);
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }

        executor.shutdown();
        try {
            if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
        return map;
    }

}
